package com.zxy.demo.java.reflect;

import java.lang.reflect.Method;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

import com.google.common.base.CaseFormat;
import com.google.common.collect.Lists;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import com.sun.istack.internal.NotNull;

/**
 * JsonConcealer.
 * 
 * 通过将get方法返回空，来达到json中隐藏某一属性的目的.
 * 
 * 暂支持，属性小驼峰命令
 * 
 * Created by zxybird on 2017/12/7.
 */
public class JsonConcealer {

  private Set<String> needHideFieldNameSet;

  Enhancer enhancer;

  public JsonConcealer(Class clazz, @NotNull List<String> needHideFieldNameList) {

    needHideFieldNameSet = needHideFieldNameList.stream().map(x -> {
      StringBuilder sb = new StringBuilder("get");
      sb.append(CaseFormat.LOWER_CAMEL.to(CaseFormat.UPPER_CAMEL, x));
      return sb.toString();
    }).collect(Collectors.toSet());

    enhancer = new Enhancer();
    enhancer.setSuperclass(clazz);
    enhancer.setClassLoader(clazz.getClassLoader());

  }

  public Object getProxy(Object object) {

    // 在内存中创建一个动态类的字节码
    // 为其指定父类
    // 除了完成继承关系外，还将父类所有的方法名反射过来，并在自己的类中
    // 创建了这些方法

    // 此刻，base不是单纯的目标类，而是增强过的目标类
    // 使用该类创建对象

    enhancer.setCallback(new MethodInterceptor() {

      private Object object;

      public MethodInterceptor setObject(Object object) {
        this.object = object;
        return this;
      }

      @Override
      public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        if (needHideFieldNameSet.contains(method.getName())) {
          return null;
        }
        return method.invoke(object, objects);
      }
    }.setObject(object));

    return enhancer.create();
  }

  public static void main(String[] args) throws InterruptedException {

    int size = 100;

    List<Person> personList = Lists.newArrayListWithExpectedSize(size);

    for (int i = 1; i <= size; i++) {
      Person person = new Person();
      person.setName(String.valueOf(10000 + i));
      person.setAge(i);

      personList.add(person);
    }

    JsonConcealer concealer = new JsonConcealer(Person.class, Lists.newArrayList("age"));

    personList = personList.stream().map(x -> (Person) concealer.getProxy(x)).collect(Collectors.toList());

    // personList.forEach(x -> {
    // System.out.println(x.getName());
    // System.out.println(x.getAge());
    // });

    JsonConcealer concealer2 = new JsonConcealer(Person.class, Lists.newArrayList("name"));

    personList = personList.stream().map(x -> (Person) concealer2.getProxy(x)).collect(Collectors.toList());

    personList.forEach(x -> {
      System.out.println(x.getName());
      System.out.println(x.getAge());
    });

    // while (true) {
    // }

    // Thread.sleep(1000 * 60 * 10);

    // Person person1 = new Person();
    // person1.setName("zxy");
    // person1.setAge(18);
    //
    // Person person2 = new Person();
    // person2.setName("zxy");
    // person2.setAge(18);
    // person1 = (Person) new JsonConcealer(person1, Lists.newArrayList("age")).getProxy();

    // System.out.println(person1.getName());
    // System.out.println(person1.getAge());

  }

}
